﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Noris.Schedule.Support.Components;
using Noris.Schedule.Support.Core;

namespace Noris.Schedule.Support.Forms
{
	/// <summary>
	/// Okno pro zobrazování chyby (na základě dat v Exception) + řízení pokračování (mail / continue / abort)
	/// </summary>
	public class ShowError : ShowForm
	{
		#region KONSTRUKCE
		/// <summary>
		/// V této metodě zdejší třída vygeneruje buttony do nadřízeného formu.
		/// </summary>
		protected override void OnButtonPanelFill()
		{
			this.MailBtn = new Button();
			this.MailBtn.Location = new System.Drawing.Point(52, 3);
			this.MailBtn.Name = "_MailBtn";
			this.MailBtn.Size = new System.Drawing.Size(100, 29);
			this.MailBtn.TabIndex = 1;
			this.MailBtn.Text = "Do mailu";
			this.MailBtn.UseVisualStyleBackColor = true;
			this.MailBtn.Click += new System.EventHandler(this.MailBtn_Click);

			this.ExitBtn = new Button();
			this.ExitBtn.Location = new System.Drawing.Point(158, 3);
			this.ExitBtn.Name = "_ExitBtn";
			this.ExitBtn.Size = new System.Drawing.Size(100, 29);
			this.ExitBtn.TabIndex = 2;
			this.ExitBtn.Text = "Ukončit program";
			this.ExitBtn.UseVisualStyleBackColor = true;
			this.ExitBtn.Click += new System.EventHandler(this.ExitBtn_Click);

			this.ContinueBtn = new Button();
			this.ContinueBtn.Location = new System.Drawing.Point(264, 3);
			this.ContinueBtn.Name = "_ContinueBtn";
			this.ContinueBtn.Size = new System.Drawing.Size(100, 29);
			this.ContinueBtn.TabIndex = 3;
			this.ContinueBtn.Text = "Pokračovat";
			this.ContinueBtn.UseVisualStyleBackColor = true;
			this.ContinueBtn.Click += new System.EventHandler(this.ContinueBtn_Click);

			this.ButtonPanel.Size = new System.Drawing.Size(369, 36);

			this.MessageImage = PicLibrary48.Error_Cached;

			this.ButtonPanel.Controls.Add(this.MailBtn);
			this.ButtonPanel.Controls.Add(this.ExitBtn);
			this.ButtonPanel.Controls.Add(this.ContinueBtn);
			this.StartDate = DateTime.Now;
		}
		protected Button MailBtn;
		protected Button ExitBtn;
		protected Button ContinueBtn;
		protected DateTime StartDate;
		#endregion
		#region ERROR PROPERTY
		/// <summary>
		/// Data o chybě. Vložením objektu se ve formuláři objeví jeho data.
		/// </summary>
		public Exception ExceptionData
		{
			get { return this._ExceptionData; }
			set { this._ExceptionData = value; this.ShowTextsInvoke(); }
		}
		private Exception _ExceptionData;
        /// <summary>
        /// Povolení pro tlačítka Pokračovat a Opakovat (true) / pouze Konec (false)
        /// </summary>
        public bool EnableContinuing
        {
            get { return this._EnableContinuing; }
            set { this._EnableContinuing = value; this.ShowTextsInvoke(); }
        }
        protected bool _EnableContinuing;
        private string _MainText;
		private string _ExtendedTextTxt;
		private string _ExtendedTextRtf;
		#endregion
		#region ZOBRAZENÍ CHYBY
        /// <summary>
        /// Řízení zobrazení obsahu okna
        /// </summary>
        protected override void ShowTexts()
        {
            this.ContinueBtn.Enabled = this.EnableContinuing;
            base.ShowTexts();
        }
		/// <summary>
		/// Metoda vrací text do hlavního rámečku.
		/// </summary>
		/// <returns></returns>
		protected override string GetTextMain()
		{
			string text = "";
			if (this.Message != null)
				text += this.Message;
			if (this.ExceptionData != null)
				text += (text.Length > 0 ? Environment.NewLine : "") +
					this._GetExceptionMessages(this.ExceptionData);
			this._MainText = text;
			return text;
		}
		/// <summary>
		/// Metoda vrací text do rozšiřujícího rámečku
		/// </summary>
		/// <returns></returns>
		protected override string GetTextExtended()
		{
			string rtfText = _GetTextExtendedRtf();
			return rtfText;
		}
		/// <summary>
		/// Vrátí text Messages z předané chyby (a z vnitřních chyb).
		/// </summary>
		/// <param name="exception"></param>
		/// <returns></returns>
		private string _GetExceptionMessages(Exception exception)
		{
			string text = "";
			Exception exc = exception;
			while (exc != null)
			{
				text += (text.Length > 0 ? Environment.NewLine : "") + exc.Message;
				exc = exc.InnerException;
			}
			return text;
		}
		/// <summary>
		/// Obsahuje první řádek chybové hlášky (z this.ExceptionData.Message anebo z this.Message).
		/// </summary>
		public string TopMessage
		{
			get
			{
				if (this.ExceptionData != null) return this.ExceptionData.Message;
				if (this.Message != null) return this.Message;
				return "Unspecified error";
			}
		}
		/// <summary>
		/// Příznak, zda se má zobrazovat button Detail.
		/// Defaultně = podle přítomnosti ExtendedText textu (= podle hodnoty ContainExtendedText).
		/// Na potomkovi lze přepsat.
		/// </summary>
		public override bool DisplayDetailButton
		{
			get
			{
				return this._ExceptionData != null;
			}
		}
		#region TEXT CHYBY RTF
		/// <summary>
		/// Vrátí text chyby RTF
		/// </summary>
		/// <returns></returns>
		private string _GetTextExtendedRtf()
		{
			string rtfText = _GetErrorMsgTemplateRtf();
			string errTxt, errTrc;
			this._GetExceptionDetailsRtf(out errTxt, out errTrc);
			rtfText = rtfText.Replace(@"\{\{Date\}\}", " " + this.StartDate.ToString("yyyy-MM-dd HH:mm:ss"));
			rtfText = rtfText.Replace(@"\{\{Version\}\}", " " + "");
			rtfText = rtfText.Replace(@"\{\{Error\}\}", errTxt);
			rtfText = rtfText.Replace(@"\{\{Trace\}\}", errTrc);
			this._ExtendedTextRtf = rtfText;
			return rtfText;
		}
		/// <summary>
		/// Vrátí šablonu detailu chyby, RTF
		/// </summary>
		/// <returns></returns>
		private string _GetErrorMsgTemplateRtf()
		{
			string template = @"{\rtf1\ansi\ansicpg1250\deff0\deflang1029{\fonttbl{\f0\fswiss\fcharset238{\*\fname Arial;}Arial CE;}}
{\colortbl ;\red128\green0\blue0;\red0\green128\blue0;}
{\*\generator Msftedit 5.41.15.1515;}\viewkind4\uc1\pard\ul\b\f0\fs24 V\'fdpis chyby aplikace GreenScheduler\ulnone\b0\fs20\par
\pard\tx994 Datum:\tab\{\{Date\}\}\par
Verze:\tab\{\{Version\}\}\par
Chyba:\{\{Error\}\}\par
Trace:\{\{Trace\}\}\par
}
 ";
			return template;
		}
		/// <summary>
		/// Sestaví texty detailní chyby v RTF formátu Messages + StackTrace chyby (a z vnitřních chyb).
		/// </summary>
		/// <param name="exception"></param>
		/// <returns></returns>
		private void _GetExceptionDetailsRtf(out string errTxt, out string errTrc)
		{
			errTxt = "";
			errTrc = "";
			if (this.ExceptionData == null) return;

			string message = "";
			string stTrace = "";
			string eol = Environment.NewLine;

			if (this.Message != null)
				message = @"\tab\cf1\b " + Library.RtfFromTxt(this.Message) + @"\cf0\b0\par" + eol;

            string stackLine = @"\tab\cf2\i\fs18 " + "".PadRight(60, '-') + @"\cf0\i0\fs20\par" + eol;

            bool isLowest = false;
			Exception exc = this.ExceptionData;
			while (exc != null)
			{
                isLowest = (exc.InnerException == null);

				message += @"\tab\cf1\b " + Library.RtfFromTxt(exc.Message) + @"\cf0\b0\par" + eol;

				string trace = exc.StackTrace;
				if (trace != null)
                {   // Trace vypisuji opačně: navrch textu dávám tu nejvnitřnější. Tedy sestavím odstavec za jednu Exception, dávám jej na začátek textu stTrace:
					string[] traceLines = trace.Split('\r', '\n');
                    string stTraceOne = "";
                    bool searchFirstNonSystem = isLowest;
					foreach (string traceLine in traceLines)
					{
                        if (!String.IsNullOrEmpty(traceLine))
                        {
                            bool isCulprit = false;
                            if (searchFirstNonSystem)
                            {
                                string line = traceLine.Trim();
                                if (line.StartsWith("v "))
                                    line = line.Substring(2);
                                if (line.StartsWith("in "))
                                    line = line.Substring(3);

                                if (!line.StartsWith("System."))
                                {   // Hledám první řádek ne System., a našel jsem jej:
                                    isCulprit = true;
                                    searchFirstNonSystem = false;
                                }
                            }
                            if (isCulprit)
                                stTraceOne += @"\tab\cf2\i\fs18\b " + Library.RtfFromTxt(traceLine.Trim()) + @"\b0\cf0\i0\fs20\par" + eol;
                            else
                                stTraceOne += @"\tab\cf2\i\fs18 " + Library.RtfFromTxt(traceLine.Trim()) + @"\cf0\i0\fs20\par" + eol;
                        }
					}
                    if (stTrace.Length == 0)
                        stTrace = stTraceOne;
                    else
                        stTrace = stTraceOne + stackLine + stTrace;
				}

				exc = exc.InnerException;
			}

			errTxt = message;
			errTrc = stTrace;
		}
		#endregion
		#region TEXT CHYBY TXT
		/// <summary>
		/// Vrátí text chyby, TXT
		/// </summary>
		/// <returns></returns>
		private string _GetTextExtendedTxt()
		{
			string txtText = _GetErrorMsgTemplateTxt();
			string errTxt, errTrc;
			this._GetExceptionDetailsTxt(out errTxt, out errTrc);
			txtText = txtText.Replace(@"\{\{Date\}\}", " " + this.StartDate.ToString("yyyy-MM-dd HH:mm:ss"));
			txtText = txtText.Replace(@"\{\{Version\}\}", " " + "");
			txtText = txtText.Replace(@"\{\{Error\}\}", errTxt);
			txtText = txtText.Replace(@"\{\{Trace\}\}", errTrc);
			txtText = txtText.Replace(@"\tab", "\t");
			this._ExtendedTextTxt = txtText;
			return txtText;
		}
		/// <summary>
		/// Vrátí šablonu detailu chyby, TXT
		/// </summary>
		/// <returns></returns>
		private string _GetErrorMsgTemplateTxt()
		{
			string template = @"Výpis chyby aplikace GreenScheduler
Datum:\tab\{\{Date\}\}\
Verze:\tab\{\{Version\}\}
Chyba:\{\{Error\}\}
Trace:\{\{Trace\}\}
 ";
			return template;
		}
		/// <summary>
		/// Sestaví texty detailní chyby v RTF formátu Messages + StackTrace chyby (a z vnitřních chyb).
		/// </summary>
		/// <param name="exception"></param>
		/// <returns></returns>
		private void _GetExceptionDetailsTxt(out string errTxt, out string errTrc)
		{
			errTxt = "";
			errTrc = "";
			if (this.ExceptionData == null) return;

			string message = "";
			string stTrace = "";
			string eol = Environment.NewLine;

			if (this.Message != null)
                message = @"\tab" + this.Message + eol;

            string stackLine = @"\tab" + "".PadRight(60, '-') + eol;

			Exception exc = this.ExceptionData;
			while (exc != null)
			{
				message += @"\tab" + exc.Message + eol;

				string trace = exc.StackTrace;
				if (trace != null)
                {   // Trace vypisuji opačně: navrch textu dávám tu nejvnitřnější. Tedy sestavím odstavec za jednu Exception, dávám jej na začátek textu stTrace:
					string[] traceLines = trace.Split('\r', '\n');
                    string stTraceOne = "";
					foreach (string traceLine in traceLines)
					{
						if (!String.IsNullOrEmpty(traceLine))
                            stTraceOne += @"\tab" + traceLine.Trim() + eol;
					}
                    if (stTrace.Length == 0)
                        stTrace = stTraceOne;
                    else
                        stTrace = stTraceOne + stackLine + stTrace;
				}

				exc = exc.InnerException;
			}

			errTxt = message;
			errTrc = stTrace;
		}
		#endregion
		#endregion
		#region EVENT HANDLERY
		/// <summary>
		/// Pošli maila
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void MailBtn_Click(object sender, EventArgs e)
		{
			string subject = "Error in GreenScheduler: " + TopMessage;
			string body = this._GetTextExtendedTxt();
			MailAdapter.SendMailWithUserNotification("dj-soft@seznam.cz", subject, body, "Informace o chybě");
		}
		/// <summary>
		/// Skonči aplikaci
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ExitBtn_Click(object sender, EventArgs e)
		{
            CancelEventArgs ce = new CancelEventArgs();
			Application.Exit(ce);
		}
		/// <summary>
		/// Pokračuj po chybě
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ContinueBtn_Click(object sender, EventArgs e)
		{
			this.Close();
		}
		#endregion
	}
}
